#include "config.h"

#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <pthread.h>
#include <getopt.h>

#define DBG_SUBSYS S_LIBYNET

#include <pthread.h>

#include "get_version.h"
#include "job_dock.h"
#include "../../ynet/sock/sock_tcp.h"
#include "../../ynet/net/net_events.h"
#include "rpc_proto.h"
#include "ynet_rpc.h"
#include "net_global.h"
#include "analysis.h"
#include "dbg.h"

typedef enum {
        PROF_NULL = 400,
        PROF_NET,
        PROF_MAX,
} prof_op_t;


typedef struct {
        uint32_t op;
        uint32_t buflen;
        char buf[0];
} msg_t;

static int __prof_seq__ = 0;
static __request_handler_func__  __request_handler__[PROF_MAX - PROF_NULL];
static char  __request_name__[PROF_MAX - PROF_NULL][__RPC_HANDLER_NAME__ ];

static void __request_set_handler(int op, __request_handler_func__ func, const char *name)
{
        YASSERT(strlen(name) + 1 < __RPC_HANDLER_NAME__ );
        strcpy(__request_name__[op - PROF_NULL], name);
        __request_handler__[op - PROF_NULL] = func;
}

static void __request_get_handler(int op, __request_handler_func__ *func, char *name)
{
        *func = __request_handler__[op - PROF_NULL];
        strcpy(name, __request_name__[op - PROF_NULL]);
}


#if 0

inline static int __prof_srv_net(const sockid_t *sockid, const msgid_t *msgid, buffer_t *_buf)
{
        ANALYSIS_BEGIN(0);
        (void) _buf;


        rpc_reply(sockid, msgid, NULL, 0);

        ANALYSIS_QUEUE(0, IO_WARN, "prof_reply");

        return 0;
}

#else

inline static int __prof_srv_net(const sockid_t *sockid, const msgid_t *msgid, buffer_t *_buf)
{
        int ret;
        buffer_t buf;
        char tmp[MAX_BUF_LEN];
        ANALYSIS_BEGIN(0);
        (void) _buf;

        rpc_reply_prep(msgid, &buf, NULL, 1);
        mbuffer_get(&buf, tmp, buf.len);

        ret = write(sockid->sd, tmp, buf.len);
        if (ret != (int)buf.len)
                UNIMPLEMENTED(__DUMP__);

        mbuffer_free(&buf);
        ANALYSIS_QUEUE(0, IO_WARN, "prof_reply");

        return 0;
}

#endif

int prof_rpc_net(const diskid_t *nid, int send, int recv)
{
        int ret;
        uint32_t count;
        msg_t *req;
        char buf[MAX_BUF_LEN];

        (void) send;
        (void) recv;

        req = (void *)buf;
        req->op = PROF_NET;
        count = 0;

        ret = rpc_request_wait("replica_rpc_getparent", nid,
                               req, sizeof(*req) + count,
                               NULL, NULL,
                               MSG_PROF, 0, _get_timeout());
        if (unlikely(ret))
                GOTO(err_ret, ret);

        return 0;
err_ret:
        return ret;
}

int prof_rpc_direct(int sd, int sendsize, int recvsize)
{
        int ret;
        buffer_t _buf;
        char buf[MAX_BUF_LEN], _req[MAX_BUF_LEN];
        msg_t *req;
        msgid_t msgid;

        DBUG("prof direct\n");

        YASSERT(sendsize + sizeof(req) <= MAX_BUF_LEN);
        (void) recvsize;

        req = (void *)_req;
        req->op = PROF_NET;
        req->buflen = sendsize;

        msgid.idx = ++__prof_seq__ % 1024;
        msgid.figerprint = ++__prof_seq__;
        ret = rpc_request_prep(&_buf, &msgid, req, sendsize + sizeof(req),
                               NULL, MSG_PROF, 1, -1);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        mbuffer_get(&_buf, buf, _buf.len);
        ret = send(sd, buf, _buf.len, MSG_DONTWAIT);
        if (ret < 0) {
                ret = errno;
                GOTO(err_free, ret);
        }

        YASSERT(ret = _buf.len);

        ret = recv(sd, buf, MAX_BUF_LEN, 0);
        if (ret < 0) {
                ret = errno;
                GOTO(err_free, ret);
        }

        mbuffer_free(&_buf);

        return 0;
err_free:
        mbuffer_free(&_buf);
err_ret:
        return ret;
}

inline static void __request_handler(void *arg)
{
        int ret;
        msg_t req;
        sockid_t sockid;
        msgid_t msgid;
        buffer_t buf;
        __request_handler_func__ handler;
        char name[MAX_NAME_LEN];

        ANALYSIS_BEGIN(0);

        request_trans(arg, &sockid, &msgid, &buf, NULL);

        if (buf.len < sizeof(req)) {
                UNIMPLEMENTED(__DUMP__);
        }

        mbuffer_get(&buf, &req, sizeof(req));

        DBUG("new job op %u\n", req.op);

        __request_get_handler(req.op, &handler, name);
        if (handler == NULL) {
                UNIMPLEMENTED(__DUMP__);
        }

        schedule_task_setname(name);

        ret = handler(&sockid, &msgid, &buf);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        mbuffer_free(&buf);

        ANALYSIS_QUEUE(0, IO_WARN, "prof_handle");

        return ;
}

int prof_rpc_init()
{
        __request_set_handler(PROF_NET, __prof_srv_net, "prof_srv_net");
      
        if (ng.daemon) {
                rpc_request_register(MSG_PROF, __request_handler, NULL);
        }

        return 0;
}
